package hr.fer.zemris.revhttp.gateway.websockets;

import hr.fer.zemris.revhttp.gateway.resources.GatewayResources;
import hr.fer.zemris.revhttp.gateway.websockets.ServerInterfaceServlet.ServerInterfaceSocket;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.util.ajax.JSON;

/**
 * @author tomek
 */
public class RequestHandler {

	private static final Map<String, Command> requestCommands;

	@SuppressWarnings("unchecked")
	private static Object getMember(Object map, String memberKey)
			throws ClassCastException {
		return ((Map<Object, Object>) map).get(memberKey);
	}

	static {
		requestCommands = new HashMap<String, Command>();
		requestCommands.put("REGISTER", new Command() {

			@Override
			public Object processJSON(Object json) {
				String pathRegex = (String) getMember(getMember(json,
						"revhttp"), "pathRegex");
				String uuid = GatewayResources
						.registerResourceRegex(pathRegex);
				if (uuid != null)
					return JSON
							.parse("{\"revhttp\" : {\"Method\" : \"REGISTER-RESPONSE\", "
									+ "\"success\" : \"true\", \"registrationKey\" : \""
									+ uuid
									+ "\", \"pathRegex\": \""
									+ pathRegex
									+ "\", \"realPrefix\" : \"localhost:8080/apps\"}}");
				else
					return JSON
							.parse("{\"revhttp\" : {\"Method\" : \"REGISTER-RESPONSE\", "
									+ "\"success\" : \"false\", \"pathRegex\": \""
									+ pathRegex
									+ "\"}}");
			}

		});
		requestCommands.put("REQUEST", new Command() {

			@Override
			public Object processJSON(Object json) {
				Object revhttp = getMember(json, "revhttp");
				String pathRegex = (String) getMember(revhttp,
						"pathRegex");
				String uuid = (String) getMember(revhttp,
						"registrationKey");
				boolean isValid = GatewayResources.isValidUUID(
						pathRegex, uuid);
				if (isValid)
					GatewayResources.addResource(pathRegex,
							getResponsibleSocket());

				return JSON
						.parse("{\"revhttp\" : {\"Method\" : \"REQUEST-RESPONSE\", "
								+ "\"pathRegex\": \""
								+ pathRegex
								+ "\", \"registrationKey\" : \""
								+ uuid
								+ "\", \"success\" : \""
								+ (isValid ? "true" : "false")
								+ "\"}}");
			}

		});
		requestCommands.put("REQUEST-RESPONSE", new Command() {

			@SuppressWarnings("unchecked")
			@Override
			public Object processJSON(Object json) {
				Object revhttp = getMember(json, "revhttp");
				String reqId = (String) getMember(
						revhttp, "requestId");
				Object http = getMember(json, "http");
				HttpServletRequest request = ProxyServlet.requestMap.get(reqId);
				HttpServletResponse response = ProxyServlet.responseMap.get(reqId);
				
				Map<Object, Object> headers = (Map<Object, Object>) getMember(http, "headers");
				
				for (Object header : headers.keySet()) {
					response.setHeader((String) header, headers.get(header).toString());
				}
				
				try {
					response.getWriter().print((String) getMember(http, "body"));
				} catch (Exception e) {
					e.printStackTrace();
				}
				Continuation continuation = ContinuationSupport.getContinuation(request);
				continuation.resume();
				return null;
			}

		});
		requestCommands.put("UNREQUEST", new Command() {

			@Override
			public Object processJSON(Object json) {
				Object revhttp = getMember(json, "revhttp");
				String pathRegex = (String) getMember(revhttp,
						"pathRegex");
				String uuid = (String) getMember(revhttp,
						"registrationKey");
				boolean isRemoved = GatewayResources.removeResource(pathRegex);

				return JSON
						.parse("{\"revhttp\" : {\"Method\" : \"UNREQUEST-RESPONSE\", "
								+ "\"pathRegex\": \""
								+ pathRegex
								+ "\", \"registrationKey\" : \""
								+ uuid
								+ "\", \"success\" : \""
								+ (isRemoved ? "true" : "false")
								+ "\"}}");
			}

		});
		requestCommands.put("UNREGISTER", new Command() {

			@Override
			public Object processJSON(Object json) {
				Object revhttp = getMember(json, "revhttp");
				String pathRegex = (String) getMember(revhttp,
						"pathRegex");
				String uuid = (String) getMember(revhttp,
						"registrationKey");
				boolean isValid = GatewayResources.isValidUUID(
						pathRegex, uuid);
				if (isValid)
					GatewayResources.unregisterResourceRegex(pathRegex);

				return JSON
						.parse("{\"revhttp\" : {\"Method\" : \"UNREGISTER-RESPONSE\", "
								+ "\"pathRegex\": \""
								+ pathRegex
								+ "\", \"registrationKey\" : \""
								+ uuid
								+ "\", \"success\" : \""
								+ (isValid ? "true" : "false")
								+ "\"}}");
			}

		});
	}

	/**
	 * @param request json object
	 * @param who
	 * @return response json object
	 */
	public static Object parseRequest(Object request,
			ServerInterfaceSocket who) {
		Command cmd = requestCommands.get(getMember(getMember(request,
				"revhttp"), "Method"));
		if (cmd == null)
			return null;
		return cmd.processJSON(request, who);
	}

	/**
	 * @author tomek
	 */
	public static abstract class Command {
		private ServerInterfaceSocket who;

		/**
		 * @param json
		 * @return response json to the request
		 */
		public abstract Object processJSON(Object json);

		/**
		 * @param json
		 * @param who
		 * @return response json to the request
		 */
		public Object processJSON(Object json, ServerInterfaceSocket who) {
			this.who = who;
			return processJSON(json);
		}

		/**
		 * @return socket responsible for execution of this command handler
		 */
		public ServerInterfaceSocket getResponsibleSocket() {
			return who;
		}
	}
}
